package com.eternal.advance.model;

import android.annotation.SuppressLint;
import android.app.Application;

import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.OnLifecycleEvent;
import androidx.databinding.ObservableArrayList;
import androidx.databinding.ObservableList;
import androidx.annotation.NonNull;

import android.view.View;

import com.alibaba.android.arouter.launcher.ARouter;
import com.eternal.advance.AdvanceFragment;
import com.eternal.advance.BR;
import com.eternal.advance.R;
import com.eternal.base.concat.BluetoothEvent;
import com.eternal.base.concat.DeviceMinModel;
import com.eternal.base.concat.DeviceModel;
import com.eternal.base.data.NotificationRepository;
import com.eternal.base.data.RepositoryInjection;
import com.eternal.base.data.ble.BleStatue;
import com.eternal.base.database.entity.Notification;
import com.eternal.base.global.ActivityEvent;
import com.eternal.base.global.BluetoothKey;
import com.eternal.base.global.ProgressEvent;
import com.eternal.base.router.RouterActivityPath;
import com.eternal.framework.binding.command.BindingAction;
import com.eternal.framework.binding.command.BindingCommand;
import com.eternal.framework.binding.command.BindingConsumer;
import com.eternal.framework.bus.Messenger;
import com.eternal.framework.bus.RxBus;
import com.eternal.framework.component.AppManager;
import com.eternal.framework.component.BaseViewModel;
import com.eternal.framework.utils.GsonUtils;
import com.eternal.framework.utils.KLog;
import com.eternal.framework.utils.RxUtils;

import org.reactivestreams.Publisher;

import java.util.Iterator;
import java.util.List;
import java.util.concurrent.TimeUnit;

import io.reactivex.Flowable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;
import me.tatarka.bindingcollectionadapter2.ItemBinding;

/**
 * Created by Administrator
 * On 2020/5/7
 * Description:
 *
 * @author Administrator
 */
public class AdvanceModel extends BaseViewModel {
    static final String ITEM_OPEN = "open item";
    static final String ITEM_EDIT = "edit item";
    private String mac;
    private byte port;
    private String time;
    private DeviceModel info;
    private NotificationRepository repository;
    private Disposable refresh, refreshDegree;
    public static int orignDegree = 0;
    public static boolean isSetChange = false;

    public AdvanceModel(@NonNull Application application) {
        super(application);
    }

    public MutableLiveData<Boolean> show = new MutableLiveData<>();
    public ObservableList<ItemModel> items = new ObservableArrayList<>();
    public ItemBinding<ItemModel> itemBinding = ItemBinding.of(BR.item, R.layout.item_notification);
    private boolean needSyncData;

    public View.OnClickListener onAutomation = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            show.setValue(false);
            start(null, BluetoothKey.AUTOMATION);
        }
    };

    public View.OnClickListener onAlarm = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            show.setValue(false);
            start(null, BluetoothKey.ALARMS);
        }
    };

    public View.OnClickListener onNotification = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            show.setValue(false);
            start(null, BluetoothKey.NOTIFICATIONS);
        }
    };

    public BindingCommand<Void> onShow = new BindingCommand<Void>(new BindingAction() {
        @Override
        public void call() {
            show.setValue(true);
        }
    });

    public BindingCommand<Void> onClose = new BindingCommand<Void>(new BindingAction() {
        @Override
        public void call() {
            show.setValue(false);
        }
    });

    public void init(final NotificationRepository repository, final String mac, byte port, String time) {
        orignDegree = (info == null ? 0 : (info.isDegree ? 1 : 2));
        this.time = time;
        this.repository = repository;
        this.mac = mac;
        this.port = port;
        initNotify();
        initMessenger();
    }

    @SuppressLint("CheckResult")
    private void initNotify() {
        if (info == null) {
            return;
        }

        //从本地数据库获取设备所有通知
        addSubscribe(repository.getNotifications(mac, port)
                .compose(RxUtils.<List<Notification>>bindToLifecycle(getLifecycleProvider()))
                .subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<List<Notification>>() {
                    @Override
                    public void accept(List<Notification> list) throws Exception {
                        items.clear();
                        for (Notification notification : list) {
                            items.add(new ItemModel(notification, info));
                        }
                    }
                }, new Consumer<Throwable>() {
                    @Override
                    public void accept(Throwable throwable) throws Exception {
                        throwable.printStackTrace();
                        KLog.e(throwable);
                    }
                })
        );
    }

    @Override
    public void registerRxBus() {
        addSubscribe(RxBus.getDefault()
                .toObservable(ActivityEvent.class)
                .subscribe(new Consumer<ActivityEvent>() {
                    @Override
                    public void accept(ActivityEvent event) {
                        if (event.what == ActivityEvent.NOTIFICATION_REFRESH) {
                            initNotify();
                        } else if (event.what == ActivityEvent.SET_DEVICE_MODEL_INFO) {             //接受控制页的DeviceModel
                            setModelInfo((DeviceModel) event.obj);
                            if (items.isEmpty()) {
                                initNotify();
                            }
                        } else if (event.what == ActivityEvent.SET_DEVICE_MODEL_INFO_DEGREE) {      //接受设置消息
                            if (info != null) {
                                AdvanceModel.orignDegree = (info.isDegree ? 1 : 2);
                            }
                            info.isDegree = ((DeviceModel) event.obj).isDegree;
                            if (items.isEmpty()) {
                                initNotify();
                            } else {
                                updateAll();
                            }
                        }
                    }
                }));

        addSubscribe(RxBus.getDefault().toObservable(BluetoothEvent.class).subscribe(new Consumer<BluetoothEvent>() {
            @Override
            public void accept(BluetoothEvent event) {
                if (event.what == BluetoothEvent.DISCONNECT && mac.equals(event.obj)) {

                } else if (event.what == BluetoothEvent.CONNECT && mac.equals(event.obj)) {
                    needSyncData = true;
                }
            }
        }));
    }

    private void setModelInfo(DeviceModel info) {
        this.info = info;
//        if(AdvanceModel.orignDegree==0){
        AdvanceModel.orignDegree = (info.isDegree ? 1 : 2);
//        }
        if (!items.isEmpty()) {
            updateAll();
        }
    }

    private void initMessenger() {
        Messenger messenger = Messenger.getDefault();
        messenger.register(this, ITEM_OPEN, ItemModel.class, new BindingConsumer<ItemModel>() {
            @Override
            public void call(ItemModel itemModel) {
//                needSyncData = itemModel.model.open;
                if (itemModel.model.open) {
                    Messenger.getDefault().send(itemModel, AdvanceFragment.OPEN_NOTIFY);
                }
                sendOpen(itemModel);
            }
        });
        messenger.register(this, ITEM_EDIT, ItemModel.class, new BindingConsumer<ItemModel>() {
            @Override
            public void call(ItemModel itemModel) {
                Notification n = itemModel.getNotification();
                start(GsonUtils.toJson(n), n.type);
            }
        });
    }

    @Override
    protected void onCleared() {
        super.onCleared();
        Messenger.getDefault().unregister(this);
    }

    private void start(String notifyJson, byte type) {
        ARouter.getInstance()
                .build(RouterActivityPath.Notification.PAGE_ADD)
                .withString(ActivityEvent.NOTIFICATION, notifyJson)
                .withString(ActivityEvent.DEVICE_TIME, time)
                .withByte(ActivityEvent.NOTIFICATION_TYPE, type)
                .withString(ActivityEvent.DEVICE_MAC, mac)
                .withByte(ActivityEvent.DEVICE_PORT, port)
                .withBoolean(ActivityEvent.DEVICE_DEGREE, info.isDegree)
                .withTransition(R.anim.right_in, R.anim.left_out)
                .navigation(AppManager.getAppManager().currentActivity());
    }

    /**
     * 打开通知
     *
     * @param item
     */
    @SuppressLint("CheckResult")
    private void sendOpen(ItemModel item) {
        final BleStatue statue = repository.getConnect(mac);
        if (statue != null) {
            stop();
            repository.openNotification(statue, item.getNotification())
                    .compose(RxUtils.<Boolean>bindToLifecycle(getLifecycleProvider()))
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .doOnSubscribe(new Consumer<Disposable>() {
                        @Override
                        public void accept(Disposable disposable) {
                            RxBus.getDefault().post(new ProgressEvent(ProgressEvent.START));
                        }
                    })
                    .subscribe(new Consumer<Boolean>() {
                        @Override
                        public void accept(Boolean result) {
                            if (!result) {
                                KLog.e("notification set error");
                            }
                            RxBus.getDefault().post(new ProgressEvent(ProgressEvent.END));
                            start();
                        }
                    }, new Consumer<Throwable>() {
                        @Override
                        public void accept(Throwable throwable) {
                            throwable.printStackTrace();
                            KLog.e(throwable);
                            start();
                        }
                    });
        }
    }

    @SuppressLint("CheckResult")
    public void remove(final ItemModel item) {
        BleStatue statue = repository.getConnect(mac);
        if (statue != null) {
            repository.removeNotification(statue, item.getNotification())
                    .compose(RxUtils.<Boolean>bindToLifecycle(getLifecycleProvider()))
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(new Consumer<Boolean>() {
                        @Override
                        public void accept(Boolean result) {
                            if (result) {
                                items.remove(item);
                            }
                        }
                    }, new Consumer<Throwable>() {
                        @Override
                        public void accept(Throwable throwable) {
                            throwable.printStackTrace();
                            KLog.e(throwable);
                        }
                    });
        }
    }

    public void updateAll() {
//        if(AdvanceModel.isSetChange){
//            AdvanceModel.isSetChange = false;
//            return;
//        }
        for (ItemModel item : items) {
            item.updateInfo(info);
        }
    }

    /**
     * 从设备获取通知消息
     */
    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    public void start() {
        BleStatue statue = repository.getConnect(mac);
        if (refresh == null && statue != null) {
                refresh = repository.getNotifications(statue, port)
                        .subscribeOn(Schedulers.io())
                        .observeOn(AndroidSchedulers.mainThread())
//                    .repeatWhen(new Function<Flowable<Object>, Publisher<?>>() {
//                        @Override
//                        public Publisher<?> apply(Flowable<Object> objectFlowable) throws Exception {
//                            return objectFlowable.delay(1, TimeUnit.SECONDS);
//                        }
//                    })
                        .subscribe(new Consumer<List<Notification>>() {
                            @Override
                            public void accept(List<Notification> list) throws Exception {
                                if (needSyncData) {
                                    needSyncData = false;
                                    //保存通知到本地数据库
                                    addSubscribe(RepositoryInjection.providerDeviceRepository()
                                            .saveNotifications(mac, port, list)
                                            .observeOn(AndroidSchedulers.mainThread())
                                            .subscribe(new Consumer<Boolean>() {
                                                @Override
                                                public void accept(Boolean aBoolean) throws Exception {
                                                    initNotify();
                                                }
                                            }));
                                } else {
                                    Notification temp, now;
                                    Iterator<Notification> iter;
                                    for (ItemModel item : items) {
                                        iter = list.iterator();
                                        while (iter.hasNext()) {
                                            temp = iter.next();
                                            now = item.getNotification();
                                            if (temp.id == now.id && temp.type == now.type) {
                                                iter.remove();
                                                if (temp.open != item.open.get()) {
                                                    item.setOpen(temp.open);
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        });
        }
        if (refreshDegree == null && statue != null) {
            refreshDegree = RepositoryInjection.providerDeviceRepository().isDegree(statue.getMac())
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .repeatWhen(new Function<Flowable<Object>, Publisher<?>>() {
                        @Override
                        public Publisher<?> apply(Flowable<Object> objectFlowable) throws Exception {
                            return objectFlowable.delay(5, TimeUnit.SECONDS);
                        }
                    })
                    .subscribe(new Consumer<Boolean>() {
                        @Override
                        public void accept(Boolean isDegree) throws Exception {
                            if (info != null && info.isDegree != isDegree) {
                                info.isDegree = isDegree;
                                setModelInfo(info);
                            }
                        }
                    }, new Consumer<Throwable>() {
                        @Override
                        public void accept(Throwable throwable) {
                            throwable.printStackTrace();
                            KLog.e(throwable);
                        }
                    });
        }
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    public void stop() {
        if (refresh != null) {
            refresh.dispose();
            refresh = null;
        }
        if (refreshDegree != null) {
            refreshDegree.dispose();
            refreshDegree = null;
        }
    }
}
